package org.xiaoxi.web;

import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.xiaoxi.async.EventModel;
import org.xiaoxi.async.EventProducer;
import org.xiaoxi.async.EventType;
import org.xiaoxi.entity.Tinyurl;
import org.xiaoxi.entity.User;
import org.xiaoxi.rateLimiter.dao.RedisClient;
import org.xiaoxi.service.TinyurlService;
import org.xiaoxi.service.UserService;
import org.xiaoxi.utils.BadUrlUtil;
import org.xiaoxi.utils.DecimalTransfer;
import org.xiaoxi.utils.HostDecodeUtil;
import org.xiaoxi.utils.JSONUtil;
import org.xiaoxi.utils.VisitLogAsyncUtil;

/**
 * Created by YanYang on 2016/6/24.
 */
@Controller
public class UrlTransferContrl {
    private static final Logger LOGGER = LoggerFactory.getLogger(UrlTransferContrl.class);

    @Autowired
    TinyurlService tinyurlService;

    @Autowired
    UserService userService;

    @Autowired
    EventProducer eventProducer;

    @Autowired
    VisitLogAsyncUtil visitLogAsyncUtil;

    @Autowired
    BadUrlUtil badUrlUtil;

    @RequestMapping(value = "/short",
            method = RequestMethod.POST,
            produces = {"application/json;charset=utf-8"})
    @ResponseBody
    public String getTinyUrl(@RequestParam(value = "username")String username,
                             @RequestParam(value = "password")String password,
                             @RequestParam(value = "longUrl")String long_url,
                             @RequestParam(value = "https",required=false) Boolean https,
                             @RequestParam(value = "seconds",required=false)Integer seconds,
                             HttpServletRequest httpServletRequest,
                             HttpSession session) {

        if (long_url == null || long_url.trim().equals("")) {
            return JSONUtil.getJSONString(0, "网址不能为空");
        }

        //获取域名
        String host = httpServletRequest.getHeader("host");
        try {
            User usr = (User)session.getAttribute("user");
            if (usr != null) {
            	long userId = usr.getId();
                if (badUrlUtil.containsBadUrl(long_url)) {
                    return JSONUtil.getJSONString(0, "此网址涉嫌敏感信息");
                }
                String short_url = tinyurlService.transferToShort_url(long_url,seconds);
                if (short_url != null) {

                    //TODO 异步把用户转化的 tinyurl 关联到用户
                    Map<String, Object> ext = new HashMap<String, Object>();
                    ext.put("userId", userId);
                    ext.put("shortId", tinyurlService.getUrlByShortUrl(short_url).getId());//DecimalTransfer.shortUrlToID(short_url)
                    ext.put("createTime", new Date().getTime());
                    eventProducer.fireEvent(new EventModel(EventType.USERS_TINYURL)
                            .setExt(ext));//TODO  作用未知
                    //拼接完整的短网址
                    String pre_https="http";
                    if(https!=null && https)
                    {
                    	pre_https="https";
                    }
                    //拼接完整的短网址
                    short_url = pre_https+"://" + host + "/" + short_url;

                    return JSONUtil.getJSONString(1, short_url);
                } else {
                    return JSONUtil.getJSONString(0, "转换为短网址失败");
                }
            } else {
                User user = new User();
                user.setUsername(username);
                user.setPassword(password);
                long userId = userService.validUser(user);
                if (userId != Long.MIN_VALUE && userId > 0) {
                    User usr1 = new User();
                    usr1.setUsername(username);
                    usr1.setPassword(password);
                    usr1.setId(userId);
                    session.setAttribute("user", usr1);
                    session.setMaxInactiveInterval(60*60*24);
                    if (badUrlUtil.containsBadUrl(long_url)) {
                        return JSONUtil.getJSONString(0, "此网址涉嫌敏感信息");
                    }
                    String short_url = tinyurlService.transferToShort_url(long_url,seconds);//XXX 增加存活时间的设置
                    if (short_url != null) {

                        Map<String, Object> ext = new HashMap<String, Object>();
                        ext.put("userId", userId);
                        ext.put("shortId", tinyurlService.getUrlByShortUrl(short_url).getId());//DecimalTransfer.shortUrlToID(short_url)
                        ext.put("createTime", new Date().getTime());
                        eventProducer.fireEvent(new EventModel(EventType.USERS_TINYURL)
                                .setExt(ext));//TODO  作用未知

                        //拼接完整的短网址
                        String pre_https="http";
                        if(https!=null && https)
                        {
                        	pre_https="https";
                        }
                        short_url = pre_https+"://" + host + "/" + short_url;

                        return JSONUtil.getJSONString(1, short_url);
                    } else {
                        return JSONUtil.getJSONString(0, "转换为短网址失败");
                    }
                } else {
                    return JSONUtil.getJSONString(0, "核查用户名和密码");
                }
            }
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
            return JSONUtil.getJSONString(0, "系统异常");
        }
    }

    
    //批量转化短连接
    @RequestMapping(value = "/shorts",
            method = RequestMethod.POST,
            produces = {"application/json;charset=utf-8"})
    @ResponseBody
    public String getTinyUrlList(@RequestParam(value = "username")String username,
                             @RequestParam(value = "password")String password,
                             @RequestParam(value = "longUrls")String long_urls,
                             @RequestParam(value = "https",required=false) Boolean https,
                             @RequestParam(value = "seconds",required=false)Integer seconds,
                             HttpServletRequest httpServletRequest,
                             HttpSession session) {

        if (long_urls == null || long_urls.trim().equals("")) {
            return JSONUtil.getJSONString(0, "网址不能为空");
        }        
        StringBuilder short_urls=new StringBuilder("");
        //获取域名
        String host = httpServletRequest.getHeader("host");
        try {
            User usr = (User)session.getAttribute("user");
            if (usr != null) {
            	long userId = usr.getId();
            	
            	//批量转化短网址
            	List<Tinyurl> list=tinyurlService.transferToShort_urls(long_urls, seconds);
            	if(list==null||list.size()<1){
            		  return JSONUtil.getJSONString(0, "转换为短网址失败");
            		
            	}
            	//获取短网址列表

            	String pre_https="http";
                if(https!=null && https)
                {
                	pre_https="https";
                }
            	for(Tinyurl tu:list){
            		String	 short_url = pre_https+"://" + host + "/" + tu.getShortUrl();
            		short_urls.append(short_url).append(",");
 
            	}

            	 return JSONUtil.getJSONString(1, short_urls.toString());
                
                
                
            } else {
                User user = new User();
                user.setUsername(username);
                user.setPassword(password);
                long userId = userService.validUser(user);
                if (userId != Long.MIN_VALUE && userId > 0) {
                    User usr1 = new User();
                    usr1.setUsername(username);
                    usr1.setPassword(password);
                    usr1.setId(userId);
                    session.setAttribute("user", usr1);
                    session.setMaxInactiveInterval(60*60*24);
                    
                  //批量转化短网址
                	List<Tinyurl> list=tinyurlService.transferToShort_urls(long_urls, seconds);
                	if(list==null||list.size()<1){
                		  return JSONUtil.getJSONString(0, "转换为短网址失败");
                		
                	}
                	//获取短网址列表
                	String pre_https="http";
                    if(https!=null && https)
                    {
                    	pre_https="https";
                    }
                	for(Tinyurl tu:list){
                		String	 short_url = pre_https+"://" + host + "/" + tu.getShortUrl();
                		short_urls.append(short_url).append(",");
     
                	}

                	 return JSONUtil.getJSONString(1, short_urls.toString());
                   
                } else {
                    return JSONUtil.getJSONString(0, "核查用户名和密码");
                }
            }
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
            return JSONUtil.getJSONString(0, "系统异常");
        }
        
        
        
    }
    
    
    
    
    @RequestMapping(value = "/{shortUrl}",
            method = RequestMethod.GET,
            produces = {"application/json;charset=utf-8"})

    public void getLongUrl(@PathVariable(value = "shortUrl")String short_url,HttpServletRequest reqeust,
                             HttpServletResponse response) {
        response.setStatus(302);
        String ip=getClientIpAddress(reqeust);
        try {
            if (short_url.length() > 7) {
                return;
            }
            /**
             * 
             * 黑名单：redis key=ip value=count time=24小时
             * 策略：
             * 	1、当天同个ip请求超过100直接拉黑
             * 返回：403
             * redis-db1
             * 
             * 
             */
          
            if(!checkIp(ip)){
            	response.setStatus(403);
            	return;
            }
            
            
            
            
            
            
            String long_url = tinyurlService.transferToLong_url(short_url,24*60*60);

            if (long_url != null) {

                // TODO 异步添加访问日志
                String host = HostDecodeUtil.getHost(long_url);
                if (host != null) {
                    long HALF_DAY = 1000 * 60 * 60 * 12;  // 12小时 （单位毫秒）
                    visitLogAsyncUtil.addToBlockingQ(host);   // 此方法中已进行了异步处理
                }

                int httpPos = long_url.indexOf("http://");
                int httpsPos = long_url.indexOf("https://");
                if (httpPos < 0 && httpsPos < 0) {
                    long_url = "http://" + long_url;
                }
                response.sendRedirect(long_url);
            } else {
//                tinyurlResult = new TinyurlResult(false, TinyurlStateEnum.TRANSFER_FAILURE.getStateInfo());
            	processFailIp(ip);
                return;
            }
        } catch (Exception e) {
        	processFailIp(ip);
            return;
        }
    }
    
    private static final int DAY_SECONDS=24*60*60;
    private static final int MAX_TIMES=20;
    private static final String[] WHITE={"101.68.92.2"};
    
    private static  boolean checkIp(String ip){
    	
    	
    	try{
    		if(Arrays.asList(WHITE).contains(ip)){
    			return true;
    		} 
    		
    		//ip请求次数限制
    		String key="ip:"+ip;
    		long count=RedisClient.incrBy(key);
    		if(count==1){
    			LOGGER.info("首次访问:"+ip+",count="+count);
    		}
    		
    		int max=getMaxTimes();
    		
    		RedisClient.expire(key, DAY_SECONDS);
    		if(count<=max){
    			LOGGER.info("效验通过ip:"+ip+",count="+count);
    			return true;
    		}else{
    			return false;
    		}
    		
    	}catch(Exception e){
    		return false;
    	}
    } 
    private static final int MIN_TIME_INTERVAL=2;
    
    private static  void processFailIp(String ip){
    	
    	
    	/**
    	 * 失败处理（一般用户不会出现连续失败的情况）
    	 * step1、第一次失败，记录失败ip key=ip_request_time:ip value=time
    	 * step2、一定时间内连续失败2次，直接把ip请求次数改成最大
    	 */
    	String key="ip_request_time:"+ip;
    	String millsStr=RedisClient.get(key);
    	Long now=System.currentTimeMillis()/1000;
    	//step1、第一次失败，记录失败ip key=ip_request_time:ip value=time
    	if(StringUtils.isBlank(millsStr)){//表示第一次
    		
    		RedisClient.set(key, ""+now, MIN_TIME_INTERVAL);
    		return ;
    	}else{
    		//step2、一定时间内连续失败2次，直接把ip请求次数改成最大
    		int max=getMaxTimes();
    		String key2="ip:"+ip;
    		RedisClient.set(key2, ""+max, DAY_SECONDS);
    		LOGGER.info("连续尝试失败,直接禁用ip:"+ip);
    	}
    	

    	
    } 
    
   public static int getMaxTimes(){
	   String keyMax="ip:reqeust_max_times";
	   int max=0;
		try{
			max=Integer.parseInt(RedisClient.get("ip:"+"reqeust_max_times"));
		}catch(Exception e){
			max=MAX_TIMES;
			RedisClient.set(keyMax, ""+MAX_TIMES);
		}
	   return max;
	   
   }
    
    
    
    
    
    public String getClientIpAddress(HttpServletRequest request) {
		String ip = request.getHeader("X-Forwarded-For");
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_CLIENT_IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_X_FORWARDED_FOR");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		}
		return ip;
	}
    
    
}
